import pivotTable from '../controllers/pivotTable'
import conditionformat from '../controllers/conditionformat'
import alternateformat from '../controllers/alternateformat'
import luckysheetSparkline from '../controllers/sparkline'
import menuButton from '../controllers/menuButton'
import dataVerificationCtrl from '../controllers/dataVerificationCtrl'
import { luckysheetdefaultstyle, luckysheet_CFiconsImg,luckysheetdefaultFont } from '../controllers/constant'
import { luckysheet_searcharray } from '../controllers/sheetSearch'
import { dynamicArrayCompute } from './dynamicArray'
import browser from './browser'
import { isRealNull, isRealNum } from './validate'
import { getMeasureText,getCellTextInfo } from './getRowlen'
import { getRealCellValue } from './getdata'
import { getBorderInfoComputeRange } from './border'
import { getSheetIndex } from '../methods/get'
import { getObjType, chatatABC, luckysheetfontformat } from '../utils/util'
import { isInlineStringCell } from '../controllers/inlineString'
import method from './method'
import Store from '../store'
import $ from 'jquery'
import locale from '../locale/locale'
import sheetmanage from '../controllers/sheetmanage'
import unescapeHtml from 'unescape-html'

function luckysheetDrawgridRowTitle(scrollHeight, drawHeight, offsetTop) {
    if (scrollHeight == null) {
        scrollHeight = $('#luckysheet-cell-main').scrollTop()
    }

    if (drawHeight == null) {
        drawHeight = Store.luckysheetTableContentHW[1]
    }

    if (offsetTop == null) {
        offsetTop = Store.columnHeaderHeight
    }

    let luckysheetTableContent = $('#luckysheetTableContent').get(0).getContext('2d')
    luckysheetTableContent.save()
    luckysheetTableContent.scale(Store.devicePixelRatio, Store.devicePixelRatio)

    luckysheetTableContent.clearRect(
        0,
        offsetTop ,
        (Store.rowHeaderWidth - 1) ,
        drawHeight
    )

    luckysheetTableContent.font = luckysheetdefaultFont()
    luckysheetTableContent.textBaseline = luckysheetdefaultstyle.textBaseline //基准线 垂直居中
    luckysheetTableContent.fillStyle = luckysheetdefaultstyle.fillStyle

    let dataset_row_st, dataset_row_ed
    dataset_row_st = luckysheet_searcharray(Store.visibledatarow, scrollHeight)
    dataset_row_ed = luckysheet_searcharray(Store.visibledatarow, scrollHeight + drawHeight)

    if (dataset_row_st == -1) {
        dataset_row_st = 0
    }
    if (dataset_row_ed == -1) {
        dataset_row_ed = Store.visibledatarow.length - 1
    }


    luckysheetTableContent.save()
    luckysheetTableContent.beginPath()
    luckysheetTableContent.rect(0, offsetTop-1, Store.rowHeaderWidth -1, drawHeight-2)
    luckysheetTableContent.clip()

    let end_r, start_r
    let bodrder05 = 0.5//Default 0.5
    let preEndR
    for (let r = dataset_row_st; r <= dataset_row_ed; r++) {
        if (r == 0) {
            start_r = -scrollHeight - 1
        }
        else {
            start_r = Store.visibledatarow[r - 1] - scrollHeight - 1
        }
        end_r = Store.visibledatarow[r] - scrollHeight

        //若超出绘制区域终止
        // if(end_r > scrollHeight + drawHeight){
        //     break;
        // }
        let firstOffset = (dataset_row_st==r)?-2:0
        let lastOffset = (dataset_row_ed==r)?-2:0
        //列标题单元格渲染前触发，return false 则不渲染该单元格
        if(!method.createHookFunction('rowTitleCellRenderBefore', r+1, {
            r:r,
            top:(start_r + offsetTop + firstOffset),
            width:Store.rowHeaderWidth -1,
            height:(end_r - start_r + 1+lastOffset-firstOffset)
        }, luckysheetTableContent)){ continue }

        if (Store.config['rowhidden'] != null && Store.config['rowhidden'][r] != null) {

        }
        else {
            luckysheetTableContent.fillStyle = '#ffffff'
            luckysheetTableContent.fillRect(
                0,
                (start_r + offsetTop + firstOffset) ,
                Store.rowHeaderWidth -1,
                (end_r - start_r + 1+lastOffset-firstOffset)
            )
            luckysheetTableContent.fillStyle = '#000000'

            //行标题栏序列号
            luckysheetTableContent.save()//save scale before draw text
            luckysheetTableContent.scale(Store.zoomRatio,Store.zoomRatio)
            let textMetrics = getMeasureText(r+1, luckysheetTableContent)
            //luckysheetTableContent.measureText(r + 1);

            let horizonAlignPos = (Store.rowHeaderWidth  - textMetrics.width) / 2
            let verticalAlignPos = (start_r + (end_r - start_r) / 2 + offsetTop)

            luckysheetTableContent.fillText(r + 1, horizonAlignPos/Store.zoomRatio, verticalAlignPos/Store.zoomRatio)
            luckysheetTableContent.restore()//restore scale after draw text
        }

        //vertical
        luckysheetTableContent.beginPath()
        luckysheetTableContent.moveTo(
            (Store.rowHeaderWidth - 2 + bodrder05) ,
             (start_r + offsetTop - 2)
        )
        luckysheetTableContent.lineTo(
            (Store.rowHeaderWidth - 2 + bodrder05) ,
             (end_r + offsetTop - 2)
        )
        luckysheetTableContent.lineWidth = 1

        luckysheetTableContent.strokeStyle = luckysheetdefaultstyle.strokeStyle
        luckysheetTableContent.stroke()
        luckysheetTableContent.closePath()

        //行标题栏横线,horizen
        if (Store.config['rowhidden'] != null && Store.config['rowhidden'][r] == null && Store.config['rowhidden'][r+1] != null) {
            luckysheetTableContent.beginPath()
            luckysheetTableContent.moveTo(
                -1,
                (end_r + offsetTop - 4 + bodrder05)
            )
            luckysheetTableContent.lineTo(
                (Store.rowHeaderWidth - 1) ,
                (end_r + offsetTop - 4 + bodrder05)
            )
            // luckysheetTableContent.lineWidth = 1;
            // luckysheetTableContent.strokeStyle = luckysheetdefaultstyle.strokeStyle;
            luckysheetTableContent.closePath()
            luckysheetTableContent.stroke()
        }
        else if(Store.config['rowhidden']==null || Store.config['rowhidden'][r] == null){
            luckysheetTableContent.beginPath()
            luckysheetTableContent.moveTo(
                -1,
                (end_r + offsetTop - 2 + bodrder05)
            )
            luckysheetTableContent.lineTo(
                (Store.rowHeaderWidth - 1) ,
                (end_r + offsetTop - 2 + bodrder05)
            )

            // luckysheetTableContent.lineWidth = 1;
            // luckysheetTableContent.strokeStyle = luckysheetdefaultstyle.strokeStyle;
            luckysheetTableContent.closePath()
            luckysheetTableContent.stroke()

        }

        if (Store.config['rowhidden'] != null && Store.config['rowhidden'][r-1] != null && preEndR!=null) {
            luckysheetTableContent.beginPath()
            luckysheetTableContent.moveTo(
                -1,
                (preEndR + offsetTop + bodrder05)
            )
            luckysheetTableContent.lineTo(
                (Store.rowHeaderWidth - 1) ,
                (preEndR + offsetTop + bodrder05)
            )
            luckysheetTableContent.closePath()
            luckysheetTableContent.stroke()
        }

        preEndR = end_r

        //列标题单元格渲染前触发，return false 则不渲染该单元格
        method.createHookFunction('rowTitleCellRenderAfter', r+1, {
            r:r,
            top:(start_r + offsetTop + firstOffset),
            width:Store.rowHeaderWidth -1,
            height:(end_r - start_r + 1+lastOffset-firstOffset)
        }, luckysheetTableContent)

    }

    //行标题栏竖线
    // luckysheetTableContent.beginPath();
    // luckysheetTableContent.moveTo(
    //     (Store.rowHeaderWidth - 2 + 0.5) ,
    //     (offsetTop - 1)
    // );
    // luckysheetTableContent.lineTo(
    //     (Store.rowHeaderWidth - 2 + 0.5) ,
    //     (Store.rh_height + offsetTop)
    // );
    // luckysheetTableContent.lineWidth = 1;
    // luckysheetTableContent.strokeStyle = luckysheetdefaultstyle.strokeStyle;
    // luckysheetTableContent.closePath();
    // luckysheetTableContent.stroke();


    //清除canvas左上角区域 防止列标题栏序列号溢出显示
    // luckysheetTableContent.clearRect(0, 0, Store.rowHeaderWidth , Store.columnHeaderHeight );

    // Must be restored twice, otherwise it will be enlarged under window.devicePixelRatio = 1.5
    luckysheetTableContent.restore()
    luckysheetTableContent.restore()

}

function luckysheetDrawgridColumnTitle(scrollWidth, drawWidth, offsetLeft) {
    if (scrollWidth == null) {
        scrollWidth = $('#luckysheet-cell-main').scrollLeft()
    }

    if (drawWidth == null) {
        drawWidth = Store.luckysheetTableContentHW[0]
    }

    if (offsetLeft == null) {
        offsetLeft = Store.rowHeaderWidth
    }

    let luckysheetTableContent = $('#luckysheetTableContent').get(0).getContext('2d')
    luckysheetTableContent.save()
    luckysheetTableContent.scale(Store.devicePixelRatio, Store.devicePixelRatio)
    luckysheetTableContent.clearRect(
        offsetLeft ,
        0,
        drawWidth ,
        (Store.columnHeaderHeight - 1)
    )


    luckysheetTableContent.font = luckysheetdefaultFont()
    luckysheetTableContent.textBaseline = luckysheetdefaultstyle.textBaseline //基准线 垂直居中
    luckysheetTableContent.fillStyle = luckysheetdefaultstyle.fillStyle

    let dataset_col_st, dataset_col_ed
    dataset_col_st = luckysheet_searcharray(Store.visibledatacolumn, scrollWidth)
    dataset_col_ed = luckysheet_searcharray(Store.visibledatacolumn, scrollWidth + drawWidth)

    if (dataset_col_st == -1) {
        dataset_col_st = 0
    }
    if (dataset_col_ed == -1) {
        dataset_col_ed = Store.visibledatacolumn.length - 1
    }

    luckysheetTableContent.save()
    luckysheetTableContent.beginPath()
    luckysheetTableContent.rect(offsetLeft-1, 0, drawWidth, Store.columnHeaderHeight -1)
    luckysheetTableContent.clip()

    // console.log(offsetLeft, 0, drawWidth, Store.columnHeaderHeight -1);

    let end_c, start_c
    let bodrder05 = 0.5//Default 0.5
    let preEndC
    for (let c = dataset_col_st; c <= dataset_col_ed; c++) {
        if (c == 0) {
            start_c = -scrollWidth
        }
        else {
            start_c = Store.visibledatacolumn[c - 1] - scrollWidth
        }
        end_c = Store.visibledatacolumn[c] - scrollWidth

        //若超出绘制区域终止
        // if(end_c > scrollWidth + drawWidth+1){
        //     break;
        // }
        let abc = chatatABC(c)
        //列标题单元格渲染前触发，return false 则不渲染该单元格
        if(!method.createHookFunction('columnTitleCellRenderBefore', abc, {
            c:c,
            left:(start_c + offsetLeft - 1),
            width:(end_c - start_c),
            height:Store.columnHeaderHeight -1
        }, luckysheetTableContent)){ continue }

        if (Store.config['colhidden'] != null && Store.config['colhidden'][c] != null) {

        }
        else {
            luckysheetTableContent.fillStyle = '#ffffff'
            luckysheetTableContent.fillRect(
                (start_c + offsetLeft - 1) ,
                0,
                (end_c - start_c) ,
                Store.columnHeaderHeight -1
            )
            luckysheetTableContent.fillStyle = '#000000'

            //列标题栏序列号
            luckysheetTableContent.save()//save scale before draw text
            luckysheetTableContent.scale(Store.zoomRatio,Store.zoomRatio)

            let textMetrics = getMeasureText(abc, luckysheetTableContent)
            //luckysheetTableContent.measureText(abc);

            let horizonAlignPos = Math.round((start_c + (end_c - start_c) / 2 + offsetLeft)  - textMetrics.width / 2)
            let verticalAlignPos = Math.round(Store.columnHeaderHeight / 2 )

            luckysheetTableContent.fillText(abc, horizonAlignPos/Store.zoomRatio, verticalAlignPos/Store.zoomRatio)
            luckysheetTableContent.restore()//restore scale after draw text
        }

        //列标题栏竖线 vertical
        if (Store.config['colhidden'] != null && Store.config['colhidden'][c] == null && Store.config['colhidden'][c+1] != null) {
            luckysheetTableContent.beginPath()
            luckysheetTableContent.moveTo(
                (end_c + offsetLeft - 4 + bodrder05) ,
                0
            )
            luckysheetTableContent.lineTo(
                (end_c + offsetLeft - 4 + bodrder05) ,
                (Store.columnHeaderHeight - 2)
            )
            luckysheetTableContent.lineWidth = 1
            luckysheetTableContent.strokeStyle = luckysheetdefaultstyle.strokeStyle
            luckysheetTableContent.closePath()
            luckysheetTableContent.stroke()
        }
        else if(Store.config['colhidden']==null || Store.config['colhidden'][c] == null) {
            luckysheetTableContent.beginPath()
            luckysheetTableContent.moveTo(
                (end_c + offsetLeft - 2 + bodrder05) ,
                0
            )
            luckysheetTableContent.lineTo(
                (end_c + offsetLeft - 2 + bodrder05) ,
                (Store.columnHeaderHeight - 2)
            )

            luckysheetTableContent.lineWidth = 1
            luckysheetTableContent.strokeStyle = luckysheetdefaultstyle.strokeStyle
            luckysheetTableContent.closePath()
            luckysheetTableContent.stroke()
        }

        if (Store.config['colhidden'] != null && Store.config['colhidden'][c-1] != null && preEndC!=null) {
            luckysheetTableContent.beginPath()
            luckysheetTableContent.moveTo(
                (preEndC + offsetLeft + bodrder05) ,
                0
            )
            luckysheetTableContent.lineTo(
                (preEndC + offsetLeft + bodrder05) ,
                (Store.columnHeaderHeight - 2)
            )
            // luckysheetTableContent.lineWidth = 1;
            // luckysheetTableContent.strokeStyle = luckysheetdefaultstyle.strokeStyle;
            luckysheetTableContent.closePath()
            luckysheetTableContent.stroke()
        }


        //horizen
        luckysheetTableContent.beginPath()
        luckysheetTableContent.moveTo(
             (start_c + offsetLeft - 1),
            (Store.columnHeaderHeight - 2 + bodrder05)
        )
        luckysheetTableContent.lineTo(
             (end_c + offsetLeft - 1),
            (Store.columnHeaderHeight - 2 + bodrder05)
        )
        // luckysheetTableContent.lineWidth = 1;

        // luckysheetTableContent.strokeStyle = luckysheetdefaultstyle.strokeStyle;
        luckysheetTableContent.stroke()
        luckysheetTableContent.closePath()

        preEndC = end_c

        method.createHookFunction('columnTitleCellRenderAfter', abc, {
            c:c,
            left:(start_c + offsetLeft - 1),
            width:(end_c - start_c),
            height:Store.columnHeaderHeight -1
        }, luckysheetTableContent)
    }

    //列标题栏横线
    // luckysheetTableContent.beginPath();
    // luckysheetTableContent.moveTo(
    //     (offsetLeft - 1) ,
    //     (Store.columnHeaderHeight - 2 + 0.5)
    // );
    // luckysheetTableContent.lineTo(
    //     (Store.ch_width + offsetLeft - 2) ,
    //     (Store.columnHeaderHeight - 2 + 0.5)
    // );
    // luckysheetTableContent.lineWidth = 1;
    // luckysheetTableContent.strokeStyle = luckysheetdefaultstyle.strokeStyle;
    // luckysheetTableContent.closePath();
    // luckysheetTableContent.stroke();

    //清除canvas左上角区域 防止列标题栏序列号溢出显示
    // luckysheetTableContent.clearRect(0, 0, Store.rowHeaderWidth , Store.columnHeaderHeight );

    // Must be restored twice, otherwise it will be enlarged under window.devicePixelRatio = 1.5
    luckysheetTableContent.restore()
    luckysheetTableContent.restore()

}

function luckysheetDrawMain(scrollWidth, scrollHeight, drawWidth, drawHeight, offsetLeft, offsetTop, columnOffsetCell, rowOffsetCell, mycanvas) {

    if(Store.flowdata == null){
        return
    }

    let sheetFile = sheetmanage.getSheetByIndex()

    // console.trace();
    clearTimeout(Store.measureTextCacheTimeOut)

    //参数未定义处理
    if (scrollWidth == null) {
        scrollWidth = $('#luckysheet-cell-main').scrollLeft()
    }
    if (scrollHeight == null) {
        scrollHeight = $('#luckysheet-cell-main').scrollTop()
    }

    if (drawWidth == null) {
        drawWidth = Store.luckysheetTableContentHW[0]
    }
    if (drawHeight == null) {
        drawHeight = Store.luckysheetTableContentHW[1]
    }

    if (offsetLeft == null) {
        offsetLeft = Store.rowHeaderWidth
    }
    if (offsetTop == null) {
        offsetTop = Store.columnHeaderHeight
    }

    if (columnOffsetCell == null) {
        columnOffsetCell = 0
    }
    if (rowOffsetCell == null) {
        rowOffsetCell = 0
    }

    //表格canvas
    let luckysheetTableContent = null
    if(mycanvas == null){
        luckysheetTableContent = $('#luckysheetTableContent').get(0).getContext('2d')
    }
    else {
        if(getObjType(mycanvas) == 'object'){
            try{
                luckysheetTableContent = mycanvas.get(0).getContext('2d')
            }
            catch(err){
                luckysheetTableContent = mycanvas
            }
        }
        else{
            luckysheetTableContent = $('#' + mycanvas).get(0).getContext('2d')
        }
    }

    luckysheetTableContent.save()
    luckysheetTableContent.scale(Store.devicePixelRatio, Store.devicePixelRatio)

    luckysheetTableContent.clearRect(
        0,
        0,
        Store.luckysheetTableContentHW[0],
        Store.luckysheetTableContentHW[1]
    )

    //表格渲染区域 起止行列下标
    let dataset_row_st,
        dataset_row_ed,
        dataset_col_st,
        dataset_col_ed

    dataset_row_st = luckysheet_searcharray(Store.visibledatarow, scrollHeight)
    dataset_row_ed = luckysheet_searcharray(Store.visibledatarow, scrollHeight + drawHeight)

    if (dataset_row_st == -1) {
        dataset_row_st = 0
    }

    dataset_row_st += rowOffsetCell

    if (dataset_row_ed == -1) {
        dataset_row_ed = Store.visibledatarow.length - 1
    }

    dataset_row_ed += rowOffsetCell

    if (dataset_row_ed >= Store.visibledatarow.length) {
        dataset_row_ed = Store.visibledatarow.length - 1
    }

    dataset_col_st = luckysheet_searcharray(Store.visibledatacolumn, scrollWidth)
    dataset_col_ed = luckysheet_searcharray(Store.visibledatacolumn, scrollWidth + drawWidth)

    if (dataset_col_st == -1) {
        dataset_col_st = 0
    }

    dataset_col_st += columnOffsetCell

    if (dataset_col_ed == -1) {
        dataset_col_ed = Store.visibledatacolumn.length - 1
    }

    dataset_col_ed += columnOffsetCell

    if (dataset_col_ed >= Store.visibledatacolumn.length) {
        dataset_col_ed = Store.visibledatacolumn.length - 1
    }

    //表格渲染区域 起止行列坐标
    let fill_row_st,
        fill_row_ed,
        fill_col_st,
        fill_col_ed

    if(dataset_row_st == 0){
        fill_row_st = 0
    }
    else{
        fill_row_st = Store.visibledatarow[dataset_row_st - 1]
    }

    fill_row_ed = Store.visibledatarow[dataset_row_ed]

    if(dataset_col_st == 0){
        fill_col_st = 0
    }
    else{
        fill_col_st = Store.visibledatacolumn[dataset_col_st - 1]
    }

    fill_col_ed = Store.visibledatacolumn[dataset_col_ed]

    //表格canvas 初始化处理
    luckysheetTableContent.fillStyle = '#ffffff'
    luckysheetTableContent.fillRect(
        (offsetLeft - 1) ,
        (offsetTop - 1) ,
        (fill_col_ed - scrollWidth) ,
        (fill_row_ed - scrollHeight)
    )
    luckysheetTableContent.font = luckysheetdefaultFont()
    // luckysheetTableContent.textBaseline = "top";
    luckysheetTableContent.fillStyle = luckysheetdefaultstyle.fillStyle

    //表格渲染区域 非空单元格行列 起止坐标
    let cellupdate = []
    let mergeCache = {}
    let borderOffset = {}

    let bodrder05 = 0.5//Default 0.5

    // 钩子函数
    method.createHookFunction('cellAllRenderBefore',Store.flowdata,sheetFile,luckysheetTableContent)

    for (let r = dataset_row_st; r <= dataset_row_ed; r++) {
        let start_r
        if (r == 0) {
            start_r = -scrollHeight - 1
        }
        else {
            start_r = Store.visibledatarow[r - 1] - scrollHeight - 1
        }

        let end_r = Store.visibledatarow[r] - scrollHeight

        if (Store.config['rowhidden'] != null && Store.config['rowhidden'][r] != null) {
            continue
        }

        for (let c = dataset_col_st; c <= dataset_col_ed; c++) {
            let start_c
            if (c == 0) {
                start_c = -scrollWidth
            }
            else {
                start_c = Store.visibledatacolumn[c - 1] - scrollWidth
            }

            let end_c = Store.visibledatacolumn[c] - scrollWidth

            if (Store.config['colhidden'] != null && Store.config['colhidden'][c] != null) {
                continue
            }

            let firstcolumnlen = Store.defaultcollen
            if (Store.config['columnlen'] != null && Store.config['columnlen'][c] != null) {
                firstcolumnlen = Store.config['columnlen'][c]
            }



            if (Store.flowdata[r] != null && Store.flowdata[r][c] != null) {
                let value = Store.flowdata[r][c]

                if(getObjType(value) == 'object' && ('mc' in value)){
                    borderOffset[r + '_' + c] = {
                        'start_r': start_r,
                        'start_c': start_c,
                        'end_r': end_r,
                        'end_c': end_c
                    }

                    if('rs' in value['mc']){
                        let key = 'r'+ r + 'c' + c
                        mergeCache[key] = cellupdate.length
                    }
                    else{
                        let key = 'r'+ value['mc'].r + 'c' + value['mc'].c
                        let margeMain = cellupdate[mergeCache[key]]

                        if(margeMain == null){
                            mergeCache[key] = cellupdate.length
                            cellupdate.push({
                                'r': r,
                                'c': c,
                                'start_c': start_c,
                                'start_r': start_r,
                                'end_r': end_r,
                                'end_c': end_c,
                                'firstcolumnlen': firstcolumnlen,
                            })
                        }
                        else{
                            if(margeMain.c == c){
                                margeMain.end_r += (end_r - start_r - 1)
                            }

                            if(margeMain.r == r){
                                margeMain.end_c += (end_c - start_c)
                                margeMain.firstcolumnlen += firstcolumnlen
                            }
                        }

                        continue
                    }
                }
            }
            else{
                //空单元格渲染前
                // if(!method.createHookFunction("cellRenderBefore", Store.flowdata[r][c], {
                //     r:r,
                //     c:c,
                //     "start_r": cellsize[1],
                //     "start_c":cellsize[0],
                //     "end_r": cellsize[3],
                //     "end_c": cellsize[2]
                // }, sheetFile,luckysheetTableContent)){ continue; }
            }


            cellupdate.push({
                'r': r,
                'c': c,
                'start_r': start_r,
                'start_c': start_c,
                'end_r': end_r,
                'end_c': end_c,
                'firstcolumnlen': firstcolumnlen,
            })
            borderOffset[r + '_' + c] = {
                'start_r': start_r,
                'start_c': start_c,
                'end_r': end_r,
                'end_c': end_c
            }
        }
    }

    //动态数组公式计算
    let dynamicArray_compute = dynamicArrayCompute(Store.luckysheetfile[getSheetIndex(Store.currentSheetIndex)]['dynamicArray'])

    //交替颜色计算
    let af_compute = alternateformat.getComputeMap()

    //条件格式计算
    let cf_compute = conditionformat.getComputeMap()

    //表格渲染区域 溢出单元格配置保存
    let cellOverflowMap = getCellOverflowMap(luckysheetTableContent, dataset_col_st, dataset_col_ed,dataset_row_st,dataset_row_ed)

    let mcArr = []

    for(let cud = 0; cud < cellupdate.length; cud++){
        let item = cellupdate[cud]
        let r = item.r,
            c = item.c,
            start_r = item.start_r,
            start_c = item.start_c,
            end_r = item.end_r,
            end_c = item.end_c
        let firstcolumnlen = item.firstcolumnlen

        if(Store.flowdata[r] == null){
            continue
        }

        // //有值单元格渲染前
        // if(!method.createHookFunction("cellRenderBefore", Store.flowdata[r][c], {
        //     r:r,
        //     c:c,
        //     "start_r": cellsize[1],
        //     "start_c":cellsize[0],
        //     "end_r": cellsize[3],
        //     "end_c": cellsize[2]
        // }, sheetFile,luckysheetTableContent)){ continue; }

        if(Store.flowdata[r][c] == null){ //空单元格
            nullCellRender(r, c, start_r, start_c, end_r, end_c,luckysheetTableContent,af_compute, cf_compute,offsetLeft,offsetTop,dynamicArray_compute,cellOverflowMap, dataset_col_st, dataset_col_ed,scrollHeight,scrollWidth,bodrder05)
        }
        else{
            let cell = Store.flowdata[r][c]
            let value = null

            if((typeof cell == 'object') && 'mc' in cell){
                mcArr.push(cellupdate[cud])
                // continue;
            }
            else{
                value = getRealCellValue(r,c)
            }

            if(value == null || value.toString().length == 0){
                nullCellRender(r, c, start_r, start_c, end_r, end_c,luckysheetTableContent,af_compute, cf_compute,offsetLeft,offsetTop,dynamicArray_compute,cellOverflowMap, dataset_col_st, dataset_col_ed,scrollHeight,scrollWidth,bodrder05)

                //sparklines渲染
                let borderfix = menuButton.borderfix(Store.flowdata, r, c)
                let cellsize = [
                     (start_c + offsetLeft + borderfix[0]),
                     (start_r + offsetTop + borderfix[1]),
                     (end_c - start_c - 3 + borderfix[2]),
                     (end_r - start_r - 3 - 1 + borderfix[3])
                ]
                sparklinesRender(r, c, cellsize[0], cellsize[1], 'luckysheetTableContent', luckysheetTableContent)
            }
            else{
                if((r + '_' + c) in dynamicArray_compute){//动态数组公式
                    value = dynamicArray_compute[r + '_' + c].v
                }

                cellRender(r, c, start_r, start_c, end_r, end_c, value,luckysheetTableContent,af_compute, cf_compute,offsetLeft,offsetTop,dynamicArray_compute,cellOverflowMap, dataset_col_st, dataset_col_ed,scrollHeight,scrollWidth,bodrder05)
            }
        }

        // method.createHookFunction("cellRenderAfter", Store.flowdata[r][c], {
        //     r:r,
        //     c:c,
        //     "start_r": start_r,
        //     "start_c": start_c,
        //     "end_r": end_r,
        //     "end_c": end_c
        // }, sheetFile,luckysheetTableContent)
    }

    //合并单元格再处理
    for(let m = 0; m < mcArr.length; m++){
        let item = mcArr[m]
        let r = item.r,
            c = item.c,
            start_r = item.start_r,
            start_c = item.start_c,
            end_r = item.end_r-1,
            end_c = item.end_c-1
        let firstcolumnlen = item.firstcolumnlen

        let cell = Store.flowdata[r][c]
        let value = null

        let margeMaindata = cell['mc']

        value = getRealCellValue(margeMaindata.r,margeMaindata.c)

        r = margeMaindata.r
        c = margeMaindata.c

        let mainCell = Store.flowdata[r][c]

        if (c == 0) {
            start_c = -scrollWidth
        }
        else {
            start_c = Store.visibledatacolumn[c - 1] - scrollWidth
        }

        if (r == 0) {
            start_r = -scrollHeight - 1
        }
        else {
            start_r = Store.visibledatarow[r - 1] - scrollHeight - 1
        }

        end_r = Store.visibledatarow[r+mainCell['mc'].rs-1] - scrollHeight
        end_c = Store.visibledatacolumn[c+mainCell['mc'].cs-1] - scrollWidth

        if(value == null || value.toString().length == 0){
            nullCellRender(r, c, start_r, start_c, end_r, end_c,luckysheetTableContent,af_compute, cf_compute,offsetLeft,offsetTop,dynamicArray_compute,cellOverflowMap, dataset_col_st, dataset_col_ed,scrollHeight,scrollWidth,bodrder05, true)

            //sparklines渲染
            let borderfix = menuButton.borderfix(Store.flowdata, r, c)
            let cellsize = [
                 (start_c + offsetLeft + borderfix[0]),
                 (start_r + offsetTop + borderfix[1]),
                 (end_c - start_c - 3 + borderfix[2]),
                 (end_r - start_r - 3 - 1  + borderfix[3])
            ]
            sparklinesRender(r, c, cellsize[0], cellsize[1], 'luckysheetTableContent', luckysheetTableContent)
        }
        else{
            if((r + '_' + c) in dynamicArray_compute){//动态数组公式
                value = dynamicArray_compute[r + '_' + c].v
            }
            cellRender(r, c, start_r, start_c, end_r, end_c, value, luckysheetTableContent,af_compute, cf_compute,offsetLeft,offsetTop,dynamicArray_compute,cellOverflowMap, dataset_col_st, dataset_col_ed,scrollHeight,scrollWidth,bodrder05, true)
        }
    }

    //数据透视表边框渲染
    for (let r = dataset_row_st; r <= dataset_row_ed; r++) {
        let start_r
        if (r == 0) {
            start_r = -scrollHeight - 1
        }
        else {
            start_r = Store.visibledatarow[r - 1] - scrollHeight - 1
        }

        let end_r = Store.visibledatarow[r] - scrollHeight

        for (let c = dataset_col_st; c <= dataset_col_ed; c++) {
            let start_c
            if (c == 0) {
                start_c = -scrollWidth
            }
            else {
                start_c = Store.visibledatacolumn[c - 1] - scrollWidth
            }

            let end_c = Store.visibledatacolumn[c] - scrollWidth


            //数据透视表
            if (!!Store.luckysheetcurrentisPivotTable && pivotTable.drawPivotTable) {
                if ((c == 0 || c == 5) && r <= 11) {
                    luckysheetTableContent.beginPath()
                    luckysheetTableContent.moveTo(
                         (end_c - 2 + bodrder05 + offsetLeft),
                         (start_r + offsetTop)
                    )
                    luckysheetTableContent.lineTo(
                         (end_c - 2 + bodrder05 + offsetLeft),
                         (end_r - 2 + bodrder05 + offsetTop)
                    )
                    luckysheetTableContent.lineWidth = 1
                    luckysheetTableContent.strokeStyle = '#000000'
                    luckysheetTableContent.closePath()
                    luckysheetTableContent.stroke()
                }

                if ((r == 2 || r == 11) && c <= 5) {
                    luckysheetTableContent.beginPath()
                    luckysheetTableContent.moveTo(
                         (start_c - 1 + offsetLeft),
                         (end_r - 2 + bodrder05 + offsetTop)
                    )
                    luckysheetTableContent.lineTo(
                         (end_c - 2 + bodrder05 + offsetLeft),
                         (end_r - 2 + bodrder05 + offsetTop)
                    )
                    luckysheetTableContent.lineWidth = 1
                    luckysheetTableContent.strokeStyle = '#000000'
                    luckysheetTableContent.closePath()
                    luckysheetTableContent.stroke()
                }

                if (r == 6 && c == 3) {
                    luckysheetTableContent.save()
                    luckysheetTableContent.font='bold 30px Arial'
                    luckysheetTableContent.fillStyle = '#626675'
                    luckysheetTableContent.textAlign='center'
                    luckysheetTableContent.fillText(
                        locale().pivotTable.title,
                         (start_c + (end_c - start_c) / 2 + 4 + offsetLeft),
                        (start_r + (end_r - start_r) / 2 - 1 + offsetTop)
                    )
                    luckysheetTableContent.restore()
                }
            }
            else if (Store.luckysheetcurrentisPivotTable) {
                if (c < pivotTable.pivotTableBoundary[1] && r < pivotTable.pivotTableBoundary[0]) {
                    luckysheetTableContent.beginPath()
                    luckysheetTableContent.moveTo(
                        (end_c - 2 + bodrder05 + offsetLeft),
                        (start_r + offsetTop)
                    )
                    luckysheetTableContent.lineTo(
                        (end_c - 2 + bodrder05 + offsetLeft),
                        (end_r - 2 + bodrder05 + offsetTop)
                    )
                    luckysheetTableContent.lineWidth = 1
                    luckysheetTableContent.strokeStyle = '#000000'
                    luckysheetTableContent.closePath()
                    luckysheetTableContent.stroke()

                    luckysheetTableContent.beginPath()
                    luckysheetTableContent.moveTo(
                        (start_c - 1 + offsetLeft),
                        (end_r - 2 + bodrder05 + offsetTop)
                    )
                    luckysheetTableContent.lineTo(
                        (end_c - 2 + offsetLeft),
                        (end_r - 2 + bodrder05 + offsetTop)
                    )
                    luckysheetTableContent.lineWidth = 1
                    luckysheetTableContent.strokeStyle = '#000000'
                    luckysheetTableContent.closePath()
                    luckysheetTableContent.stroke()
                }
            }
        }
    }

    //边框单独渲染
    if(Store.config['borderInfo'] != null && Store.config['borderInfo'].length > 0){
        //边框渲染
        let borderLeftRender = function(style, color, start_r, start_c, end_r, end_c, offsetLeft, offsetTop, canvas){
            let linetype = style

            let m_st =  (start_c - 2 + bodrder05 + offsetLeft)
            let m_ed =  (start_r + offsetTop-1)
            let line_st =  (start_c - 2 + bodrder05 + offsetLeft)
            let line_ed =  (end_r - 2 + bodrder05 + offsetTop)
            canvas.save()
            menuButton.setLineDash(canvas, linetype, 'v', m_st, m_ed, line_st, line_ed)

            canvas.strokeStyle = color

            canvas.stroke()
            canvas.closePath()
            canvas.restore()
        }

        let borderRightRender = function(style, color, start_r, start_c, end_r, end_c, offsetLeft, offsetTop, canvas){
            let linetype = style

            let m_st =  (end_c - 2 + bodrder05 + offsetLeft)
            let m_ed =  (start_r + offsetTop-1)
            let line_st =  (end_c - 2 + bodrder05 + offsetLeft)
            let line_ed =  (end_r - 2 + bodrder05 + offsetTop)
            canvas.save()
            menuButton.setLineDash(canvas, linetype, 'v', m_st, m_ed, line_st, line_ed)

            canvas.strokeStyle = color

            canvas.stroke()
            canvas.closePath()
            canvas.restore()
        }

        let borderBottomRender = function(style, color, start_r, start_c, end_r, end_c, offsetLeft, offsetTop, canvas){
            let linetype = style

            let m_st =  (start_c - 2 + bodrder05 + offsetLeft)
            let m_ed =  (end_r - 2 + bodrder05 + offsetTop)
            let line_st =  (end_c - 2 + bodrder05 + offsetLeft)
            let line_ed =  (end_r - 2 + bodrder05 + offsetTop)
            canvas.save()
            menuButton.setLineDash(canvas, linetype, 'h', m_st, m_ed, line_st, line_ed)

            canvas.strokeStyle = color

            canvas.stroke()
            canvas.closePath()
            canvas.restore()
        }

        let borderTopRender = function(style, color, start_r, start_c, end_r, end_c, offsetLeft, offsetTop, canvas){
            let linetype = style

            let m_st =  (start_c - 2 + bodrder05 + offsetLeft)
            let m_ed =  (start_r - 1 + bodrder05 + offsetTop)
            let line_st =  (end_c - 2 + bodrder05 + offsetLeft)
            let line_ed =  (start_r - 1 + bodrder05 + offsetTop)
            canvas.save()
            menuButton.setLineDash(canvas, linetype, 'h', m_st, m_ed, line_st, line_ed)

            canvas.strokeStyle = color

            canvas.stroke()
            canvas.closePath()
            canvas.restore()
        }

        let borderInfoCompute = getBorderInfoComputeRange(dataset_row_st,dataset_row_ed,dataset_col_st,dataset_col_ed)

        for(let x in borderInfoCompute){
            //let bd_r = x.split("_")[0], bd_c = x.split("_")[1];

            let bd_r = x.substr(0, x.indexOf('_'))
            let bd_c = x.substr(x.indexOf('_') + 1)

            // if(bd_r < dataset_row_st || bd_r > dataset_row_ed || bd_c < dataset_col_st || bd_c > dataset_col_ed){
            //     continue;
            // }

            if(borderOffset[bd_r + '_' + bd_c]){
                let start_r = borderOffset[bd_r + '_' + bd_c].start_r
                let start_c = borderOffset[bd_r + '_' + bd_c].start_c
                let end_r = borderOffset[bd_r + '_' + bd_c].end_r
                let end_c = borderOffset[bd_r + '_' + bd_c].end_c

                let cellOverflow_colInObj = cellOverflow_colIn(cellOverflowMap, bd_r, bd_c, dataset_col_st, dataset_col_ed)

                let borderLeft = borderInfoCompute[x].l
                if(borderLeft != null && (!cellOverflow_colInObj.colIn || cellOverflow_colInObj.stc == bd_c)){
                    borderLeftRender(borderLeft.style, borderLeft.color, start_r, start_c, end_r, end_c, offsetLeft, offsetTop, luckysheetTableContent)
                }

                let borderRight = borderInfoCompute[x].r
                if(borderRight != null && (!cellOverflow_colInObj.colIn || cellOverflow_colInObj.colLast)){
                    borderRightRender(borderRight.style, borderRight.color, start_r, start_c, end_r, end_c, offsetLeft, offsetTop, luckysheetTableContent)
                }

                let borderTop = borderInfoCompute[x].t
                if(borderTop != null){
                    borderTopRender(borderTop.style, borderTop.color, start_r, start_c, end_r, end_c, offsetLeft, offsetTop, luckysheetTableContent)
                }

                let borderBottom = borderInfoCompute[x].b
                if(borderBottom != null){
                    borderBottomRender(borderBottom.style, borderBottom.color, start_r, start_c, end_r, end_c, offsetLeft, offsetTop, luckysheetTableContent)
                }
            }
        }
    }

    //渲染表格时有尾列时，清除右边灰色区域，防止表格有值溢出
    if(dataset_col_ed == Store.visibledatacolumn.length - 1){
        luckysheetTableContent.clearRect(
            (fill_col_ed - scrollWidth + offsetLeft) - 1 ,
            (offsetTop) - 1 ,
            (Store.ch_width - Store.visibledatacolumn[dataset_col_ed]) ,
            (fill_row_ed - scrollHeight)
        )
    }

    luckysheetTableContent.restore()

    Store.measureTextCacheTimeOut = setTimeout(() => {
        Store.measureTextCache = {}
        Store.measureTextCellInfoCache = {}
        Store.cellOverflowMapCache = {}
    }, 100)

}


//sparklines渲染
let sparklinesRender = function(r, c, offsetX, offsetY, canvasid, ctx){
    if(Store.flowdata[r] == null || Store.flowdata[r][c] == null){
        return
    }

    let sparklines = Store.flowdata[r][c].spl
    if(sparklines != null){
        if(typeof sparklines == 'string'){
            sparklines = new Function('return ' + sparklines)()
        }

        if(getObjType(sparklines) == 'object'){
            let temp1 = sparklines
            let x = temp1.offsetX
            let y = temp1.offsetY
            x = x == null ? 0 : x
            y = y == null ? 0 : y
            luckysheetSparkline.render(
                temp1.shapeseq,
                temp1.shapes,
                offsetX + x,
                offsetY + y,
                temp1.pixelWidth,
                temp1.pixelHeight,
                canvasid,
                ctx
            )
        }
        else if(getObjType(sparklines) == 'array' && getObjType(sparklines[0]) == 'object'){
            for(let i = 0; i < sparklines.length; i++){
                let temp1 = sparklines[i]
                let x = temp1.offsetX
                let y = temp1.offsetY
                x = x == null ? 0 : x
                y = y == null ? 0 : y
                luckysheetSparkline.render(
                    temp1.shapeseq,
                    temp1.shapes,
                    offsetX + x,
                    offsetY + y,
                    temp1.pixelWidth,
                    temp1.pixelHeight,
                    canvasid,
                    ctx
                )
            }
        }
    }
}

//空白单元格渲染
let nullCellRender = function(r, c, start_r, start_c, end_r, end_c,luckysheetTableContent,af_compute,cf_compute,offsetLeft,offsetTop,dynamicArray_compute,cellOverflowMap, dataset_col_st, dataset_col_ed,scrollHeight,scrollWidth,bodrder05,isMerge){
    let checksAF = alternateformat.checksAF(r, c, af_compute) //交替颜色
    let checksCF = conditionformat.checksCF(r, c, cf_compute) //条件格式

    let borderfix = menuButton.borderfix(Store.flowdata, r, c)

    //背景色
    let fillStyle = menuButton.checkstatus(Store.flowdata, r, c , 'bg')

    if(checksAF != null && checksAF[1] != null){//交替颜色
        fillStyle = checksAF[1]
    }

    if(checksCF != null && checksCF['cellColor'] != null){//条件格式
        fillStyle = checksCF['cellColor']
    }

    if(Store.flowdata[r][c] != null && Store.flowdata[r][c].tc != null){//标题色
        fillStyle = Store.flowdata[r][c].tc
    }

    if(fillStyle==null){
        luckysheetTableContent.fillStyle = '#FFFFFF'
    }
    else{
        luckysheetTableContent.fillStyle = fillStyle
    }

    // 这里计算canvas需要绘制的矩形范围时,需要留下原本单元格边框的位置
    // 让 fillRect 绘制矩形的起始xy坐标增加1,绘制长宽减少1

    let cellsize = [
        (start_c + offsetLeft + borderfix[0] + 1),
        (start_r + offsetTop  + borderfix[1] + 1),
        (end_c - start_c + borderfix[2]-(isMerge?1:0) - 1),
        (end_r - start_r + borderfix[3] - 1)
    ]

    //单元格渲染前，考虑到合并单元格会再次渲染一遍，统一放到这里
    if(!method.createHookFunction('cellRenderBefore', Store.flowdata[r][c], {
        r:r,
        c:c,
        'start_r': cellsize[1],
        'start_c':cellsize[0],
        'end_r': cellsize[3] + cellsize[1],
        'end_c': cellsize[2] + cellsize[0]
    }, sheetmanage.getSheetByIndex(),luckysheetTableContent)){ return }

    luckysheetTableContent.fillRect(cellsize[0], cellsize[1], cellsize[2], cellsize[3])

    if((r + '_' + c) in dynamicArray_compute){
        let value = dynamicArray_compute[r + '_' + c].v

        luckysheetTableContent.fillStyle = '#000000'
        //文本宽度和高度
        let fontset = luckysheetdefaultFont()
        luckysheetTableContent.font = fontset

        //水平对齐 (默认为1，左对齐)
        let horizonAlignPos = (start_c + 4 + offsetLeft)

        //垂直对齐 (默认为2，下对齐)
        let verticalFixed = browser.luckysheetrefreshfixed()
        let verticalAlignPos = (end_r + offsetTop - 2)
        luckysheetTableContent.textBaseline = 'bottom'

        luckysheetTableContent.fillText(value == null ? '' : value, horizonAlignPos, verticalAlignPos)
    }

    //若单元格有批注
    if(Store.flowdata[r][c] != null && Store.flowdata[r][c].ps != null){
        let ps_w = 8*Store.zoomRatio, ps_h = 8*Store.zoomRatio
        luckysheetTableContent.beginPath()
        luckysheetTableContent.moveTo( (end_c + offsetLeft - 1- ps_w),  (start_r + offsetTop))
        luckysheetTableContent.lineTo( (end_c + offsetLeft - 1),  (start_r + offsetTop))
        luckysheetTableContent.lineTo( (end_c + offsetLeft - 1),  (start_r + offsetTop + ps_h))
        luckysheetTableContent.fillStyle = '#FC6666'
        luckysheetTableContent.fill()
        luckysheetTableContent.closePath()
    }

    //此单元格 与  溢出单元格关系
    let cellOverflow_colInObj = cellOverflow_colIn(cellOverflowMap, r, c, dataset_col_st, dataset_col_ed)

    //此单元格 为 溢出单元格渲染范围最后一列，绘制溢出单元格内容
    if(cellOverflow_colInObj.colLast){
        cellOverflowRender(
            cellOverflow_colInObj.rowIndex,
            cellOverflow_colInObj.colIndex,
            cellOverflow_colInObj.stc,
            cellOverflow_colInObj.edc,
            luckysheetTableContent,
            scrollHeight,
            scrollWidth,
            offsetLeft,offsetTop,af_compute, cf_compute
        )
    }

    //即溢出单元格跨此单元格，此单元格不绘制右边框
    if(!cellOverflow_colInObj.colIn || cellOverflow_colInObj.colLast){

        // 右边框
        // 无论是否有背景色，都默认绘制右边框
        if(!Store.luckysheetcurrentisPivotTable && Store.showGridLines){
            luckysheetTableContent.beginPath()
            luckysheetTableContent.moveTo(
                (end_c + offsetLeft - 2 + bodrder05),
                (start_r + offsetTop)
            )
            luckysheetTableContent.lineTo(
                (end_c + offsetLeft - 2 + bodrder05),
                (end_r + offsetTop)
            )
            luckysheetTableContent.lineWidth = 1

            luckysheetTableContent.strokeStyle = luckysheetdefaultstyle.strokeStyle
            luckysheetTableContent.stroke()
            luckysheetTableContent.closePath()
        }
    }

    // 下边框
    // 无论是否有背景色，都默认绘制下边框
    if(!Store.luckysheetcurrentisPivotTable && Store.showGridLines){
        luckysheetTableContent.beginPath()
        luckysheetTableContent.moveTo(
            (start_c + offsetLeft - 1),
            (end_r + offsetTop - 2 + bodrder05)
        )
        luckysheetTableContent.lineTo(
            (end_c + offsetLeft - 1),
            (end_r + offsetTop - 2 + bodrder05)
        )
        luckysheetTableContent.lineWidth = 1

        luckysheetTableContent.strokeStyle = luckysheetdefaultstyle.strokeStyle
        luckysheetTableContent.stroke()
        luckysheetTableContent.closePath()
    }

    // 单元格渲染后
    method.createHookFunction('cellRenderAfter', Store.flowdata[r][c], {
        r:r,
        c:c,
        'start_r': cellsize[1],
        'start_c':cellsize[0],
        'end_r': cellsize[3] + cellsize[1],
        'end_c': cellsize[2] + cellsize[0]
    }, sheetmanage.getSheetByIndex(),luckysheetTableContent)
}


let cellRender = function(r, c, start_r, start_c, end_r, end_c, value, luckysheetTableContent,af_compute, cf_compute,offsetLeft,offsetTop,dynamicArray_compute,cellOverflowMap, dataset_col_st, dataset_col_ed,scrollHeight,scrollWidth,bodrder05,isMerge){
    let cell = Store.flowdata[r][c]
    let cellWidth = end_c - start_c - 2
    let cellHeight = end_r - start_r - 2
    let space_width = 2, space_height = 2 //宽高方向 间隙

    //水平对齐
    let horizonAlign = menuButton.checkstatus(Store.flowdata, r, c, 'ht')
    //垂直对齐
    let verticalAlign = menuButton.checkstatus(Store.flowdata, r, c, 'vt')

    //交替颜色
    let checksAF = alternateformat.checksAF(r, c, af_compute)
    //条件格式
    let checksCF = conditionformat.checksCF(r, c, cf_compute)

    //单元格 背景颜色
    let fillStyle = menuButton.checkstatus(Store.flowdata, r, c, 'bg')
    if(checksAF != null && checksAF[1] != null){ //若单元格有交替颜色 背景颜色
        fillStyle = checksAF[1]
    }
    if(checksCF != null && checksCF['cellColor'] != null){ //若单元格有条件格式 背景颜色
        fillStyle = checksCF['cellColor']
    }
    // luckysheetTableContent.textBaseline = 'top';
    if(fillStyle==null){
        luckysheetTableContent.fillStyle = '#FFFFFF'
    }
    else{
        luckysheetTableContent.fillStyle = fillStyle
    }

    let borderfix = menuButton.borderfix(Store.flowdata, r, c)

    // 这里计算canvas需要绘制的矩形范围时,需要留下原本单元格边框的位置
    // 让 fillRect 绘制矩形的起始xy坐标增加1,绘制长宽减少1

    let cellsize = [
        (start_c + offsetLeft + borderfix[0] + 1),
        (start_r + offsetTop  + borderfix[1] + 1),
        (end_c - start_c + borderfix[2]-(isMerge?1:0) - 1),
        (end_r - start_r + borderfix[3] + 1)
    ]

    //单元格渲染前，考虑到合并单元格会再次渲染一遍，统一放到这里
    if(!method.createHookFunction('cellRenderBefore', Store.flowdata[r][c], {
        r:r,
        c:c,
        'start_r': cellsize[1],
        'start_c':cellsize[0],
        'end_r': cellsize[3] + cellsize[1],
        'end_c': cellsize[2] + cellsize[0]
    }, sheetmanage.getSheetByIndex(),luckysheetTableContent)){ return }


    luckysheetTableContent.fillRect(cellsize[0], cellsize[1], cellsize[2], cellsize[3])

    let dataVerification = dataVerificationCtrl.dataVerification

    if(dataVerification != null && dataVerification[r + '_' + c] != null && !dataVerificationCtrl.validateCellData(unescapeHtml(value), dataVerification[r + '_' + c])){
        //单元格左上角红色小三角标示
        let dv_w = 5 * Store.zoomRatio, dv_h = 5 * Store.zoomRatio //红色小三角宽高

        luckysheetTableContent.beginPath()
        luckysheetTableContent.moveTo(
            (start_c + offsetLeft),
            (start_r + offsetTop)
        )
        luckysheetTableContent.lineTo(
            (start_c + offsetLeft + dv_w),
            (start_r + offsetTop)
        )
        luckysheetTableContent.lineTo(
            (start_c + offsetLeft),
            (start_r + offsetTop + dv_h)
        )
        luckysheetTableContent.fillStyle = '#FC6666'
        luckysheetTableContent.fill()
        luckysheetTableContent.closePath()
    }

    //若单元格有批注（单元格右上角红色小三角标示）
    if(cell.ps != null){
        let ps_w = 8*Store.zoomRatio, ps_h = 8*Store.zoomRatio //红色小三角宽高

        luckysheetTableContent.beginPath()
        luckysheetTableContent.moveTo(
            (end_c + offsetLeft - ps_w),
            (start_r + offsetTop)
        )
        luckysheetTableContent.lineTo(
            (end_c + offsetLeft),
            (start_r + offsetTop)
        )
        luckysheetTableContent.lineTo(
            (end_c + offsetLeft),
            (start_r + offsetTop + ps_h)
        )
        luckysheetTableContent.fillStyle = '#FC6666'
        luckysheetTableContent.fill()
        luckysheetTableContent.closePath()
    }

    //若单元格强制为字符串，则显示绿色小三角
    if(cell.qp==1 && isRealNum(cell.v)){
        let ps_w = 6*Store.zoomRatio, ps_h = 6*Store.zoomRatio //红色小三角宽高

        luckysheetTableContent.beginPath()
        luckysheetTableContent.moveTo(
            (start_c + offsetLeft + ps_w-1),
            (start_r + offsetTop)
        )
        luckysheetTableContent.lineTo(
            (start_c + offsetLeft-1),
            (start_r + offsetTop)
        )
        luckysheetTableContent.lineTo(
            (start_c + offsetLeft-1),
            (start_r + offsetTop + ps_h)
        )
        luckysheetTableContent.fillStyle = '#487f1e'
        luckysheetTableContent.fill()
        luckysheetTableContent.closePath()
    }

    //溢出单元格
    let cellOverflow_bd_r_render = true //溢出单元格右边框是否需要绘制
    let cellOverflow_colInObj = cellOverflow_colIn(cellOverflowMap, r, c, dataset_col_st, dataset_col_ed)

    if(cell.tb == '1' && cellOverflow_colInObj.colIn){
        //此单元格 为 溢出单元格渲染范围最后一列，绘制溢出单元格内容
        if(cellOverflow_colInObj.colLast){
            cellOverflowRender(
                cellOverflow_colInObj.rowIndex,
                cellOverflow_colInObj.colIndex,
                cellOverflow_colInObj.stc,
                cellOverflow_colInObj.edc,
                luckysheetTableContent,
                scrollHeight,
                scrollWidth,offsetLeft,offsetTop,af_compute, cf_compute
            )
        }
        else{
            cellOverflow_bd_r_render = false
        }
    }
    //数据验证 复选框
    else if(dataVerification != null && dataVerification[r + '_' + c] != null && dataVerification[r + '_' + c].type == 'checkbox'){
        let pos_x = start_c + offsetLeft
        let pos_y = start_r + offsetTop + 1

        luckysheetTableContent.save()
        luckysheetTableContent.beginPath()
        luckysheetTableContent.rect(pos_x, pos_y, cellWidth, cellHeight)
        luckysheetTableContent.clip()
        luckysheetTableContent.scale(Store.zoomRatio,Store.zoomRatio)

        let measureText = getMeasureText(value, luckysheetTableContent)
        let textMetrics = measureText.width + 14
        let oneLineTextHeight = measureText.actualBoundingBoxDescent + measureText.actualBoundingBoxAscent

        let horizonAlignPos = (pos_x + space_width)  //默认为1，左对齐
        if(horizonAlign == '0'){ //居中对齐
            horizonAlignPos = (pos_x + cellWidth / 2)  - (textMetrics / 2)
        }
        else if(horizonAlign == '2'){ //右对齐
            horizonAlignPos = (pos_x + cellWidth - space_width)  - textMetrics
        }

        let verticalCellHeight = cellHeight > oneLineTextHeight ? cellHeight : oneLineTextHeight

        let verticalAlignPos_text = (pos_y + verticalCellHeight - space_height)  //文本垂直方向基准线
        luckysheetTableContent.textBaseline = 'bottom'
        let verticalAlignPos_checkbox = verticalAlignPos_text - 13 * Store.zoomRatio

        if(verticalAlign == '0'){ //居中对齐
            verticalAlignPos_text = (pos_y + verticalCellHeight / 2)
            luckysheetTableContent.textBaseline = 'middle'
            verticalAlignPos_checkbox = verticalAlignPos_text - 6 * Store.zoomRatio
        }
        else if(verticalAlign == '1'){ //上对齐
            verticalAlignPos_text = (pos_y + space_height)
            luckysheetTableContent.textBaseline = 'top'
            verticalAlignPos_checkbox = verticalAlignPos_text + 1 * Store.zoomRatio
        }

        horizonAlignPos = horizonAlignPos / Store.zoomRatio
        verticalAlignPos_text = verticalAlignPos_text / Store.zoomRatio
        verticalAlignPos_checkbox = verticalAlignPos_checkbox / Store.zoomRatio

        //复选框
        luckysheetTableContent.lineWidth = 1
        luckysheetTableContent.strokeStyle = '#000'
        luckysheetTableContent.strokeRect(horizonAlignPos, verticalAlignPos_checkbox, 10, 10)

        if(dataVerification[r + '_' + c].checked){
            luckysheetTableContent.beginPath()
            luckysheetTableContent.lineTo(
                horizonAlignPos + 1,
                verticalAlignPos_checkbox + 6
            )
            luckysheetTableContent.lineTo(
                horizonAlignPos + 4,
                verticalAlignPos_checkbox + 9
            )
            luckysheetTableContent.lineTo(
                horizonAlignPos + 9,
                verticalAlignPos_checkbox + 2
            )
            luckysheetTableContent.stroke()
            luckysheetTableContent.closePath()
        }

        //文本
        luckysheetTableContent.fillStyle = menuButton.checkstatus(Store.flowdata, r, c , 'fc')
        luckysheetTableContent.fillText(value == null ? '' : unescapeHtml(value), horizonAlignPos + 14, verticalAlignPos_text)

        luckysheetTableContent.restore()
    }
    else{
        //若单元格有条件格式数据条
        if(checksCF != null && checksCF['dataBar'] != null && checksCF['dataBar']['valueLen'] && checksCF['dataBar']['valueLen'].toString() !== 'NaN'){
            let x =  (start_c + offsetLeft + space_width)
            let y =  (start_r + offsetTop + space_height)
            let w =  (cellWidth - space_width * 2)
            let h =  (cellHeight - space_height * 2)

            let valueType = checksCF['dataBar']['valueType']
            let valueLen = checksCF['dataBar']['valueLen']
            let format = checksCF['dataBar']['format']

            if(valueType == 'minus'){
                //负数
                let minusLen = checksCF['dataBar']['minusLen']

                if(format.length > 1){
                    //渐变
                    let my_gradient = luckysheetTableContent.createLinearGradient(
                        x + w * minusLen * (1 - valueLen),
                        y,
                        x + w * minusLen,
                        y
                    )
                    my_gradient.addColorStop(0, '#ffffff')
                    my_gradient.addColorStop(1, '#ff0000')

                    luckysheetTableContent.fillStyle = my_gradient
                }
                else{
                    //单色
                    luckysheetTableContent.fillStyle = '#ff0000'
                }

                luckysheetTableContent.fillRect(
                    x + w * minusLen * (1 - valueLen),
                    y,
                    w * minusLen * valueLen,
                    h
                )

                luckysheetTableContent.beginPath()
                luckysheetTableContent.moveTo(
                    x + w * minusLen * (1 - valueLen),
                    y
                )
                luckysheetTableContent.lineTo(
                    x + w * minusLen * (1 - valueLen),
                    y + h
                )
                luckysheetTableContent.lineTo(
                    x + w * minusLen,
                    y + h
                )
                luckysheetTableContent.lineTo(
                    x + w * minusLen,
                    y
                )
                luckysheetTableContent.lineTo(
                    x + w * minusLen * (1 - valueLen),
                    y
                )
                luckysheetTableContent.lineWidth = 1
                luckysheetTableContent.strokeStyle = '#ff0000'
                luckysheetTableContent.stroke()
                luckysheetTableContent.closePath()
            }
            else if(valueType == 'plus'){
                //正数
                let plusLen = checksCF['dataBar']['plusLen']

                if(plusLen == 1){
                    if(format.length > 1){
                        //渐变
                        let my_gradient = luckysheetTableContent.createLinearGradient(
                            x,
                            y,
                            x + w * valueLen,
                            y
                        )
                        my_gradient.addColorStop(0, format[0])
                        my_gradient.addColorStop(1, format[1])

                        luckysheetTableContent.fillStyle = my_gradient
                    }
                    else{
                        //单色
                        luckysheetTableContent.fillStyle = format[0]
                    }

                    luckysheetTableContent.fillRect(
                        x,
                        y,
                        w * valueLen,
                        h
                    )

                    luckysheetTableContent.beginPath()
                    luckysheetTableContent.moveTo(
                        x,
                        y
                    )
                    luckysheetTableContent.lineTo(
                        x,
                        y + h
                    )
                    luckysheetTableContent.lineTo(
                        x + w * valueLen,
                        y + h
                    )
                    luckysheetTableContent.lineTo(
                        x + w * valueLen,
                        y
                    )
                    luckysheetTableContent.lineTo(
                        x,
                        y
                    )
                    luckysheetTableContent.lineWidth = 1
                    luckysheetTableContent.strokeStyle = format[0]
                    luckysheetTableContent.stroke()
                    luckysheetTableContent.closePath()
                }
                else{
                    let minusLen = checksCF['dataBar']['minusLen']

                    if(format.length > 1){
                        //渐变
                        let my_gradient = luckysheetTableContent.createLinearGradient(
                            x + w * minusLen,
                            y,
                            x + w * minusLen + w * plusLen * valueLen,
                            y
                        )
                        my_gradient.addColorStop(0, format[0])
                        my_gradient.addColorStop(1, format[1])

                        luckysheetTableContent.fillStyle = my_gradient
                    }
                    else{
                        //单色
                        luckysheetTableContent.fillStyle = format[0]
                    }

                    luckysheetTableContent.fillRect(
                        x + w * minusLen,
                        y,
                        w * plusLen * valueLen,
                        h
                    )

                    luckysheetTableContent.beginPath()
                    luckysheetTableContent.moveTo(
                        x + w * minusLen,
                        y
                    )
                    luckysheetTableContent.lineTo(
                        x + w * minusLen,
                        y + h
                    )
                    luckysheetTableContent.lineTo(
                        x + w * minusLen + w * plusLen * valueLen,
                        y + h
                    )
                    luckysheetTableContent.lineTo(
                        x + w * minusLen + w * plusLen * valueLen,
                        y
                    )
                    luckysheetTableContent.lineTo(
                        x + w * minusLen,
                        y
                    )
                    luckysheetTableContent.lineWidth = 1
                    luckysheetTableContent.strokeStyle = format[0]
                    luckysheetTableContent.stroke()
                    luckysheetTableContent.closePath()
                }
            }
        }

        let pos_x = start_c + offsetLeft
        let pos_y = start_r + offsetTop + 1

        luckysheetTableContent.save()
        luckysheetTableContent.beginPath()
        luckysheetTableContent.rect(pos_x , pos_y, cellWidth , cellHeight )
        luckysheetTableContent.clip()
        luckysheetTableContent.scale(Store.zoomRatio,Store.zoomRatio)


        let textInfo = getCellTextInfo(cell , luckysheetTableContent, {
            cellWidth:cellWidth,
            cellHeight:cellHeight,
            space_width:space_width,
            space_height:space_height,
            r:r,
            c:c
        })

        //若单元格有条件格式图标集
        if(checksCF != null && checksCF['icons'] != null && textInfo.type=='plain'){
            let l = checksCF['icons']['left']
            let t = checksCF['icons']['top']

            let value = textInfo.values[0]
            let horizonAlignPos = pos_x +  value.left
            let verticalAlignPos = pos_y + value.top- textInfo.textHeightAll

            if(verticalAlign == '0'){ //居中对齐
                verticalAlignPos = pos_y + cellHeight/2 - textInfo.textHeightAll/2
            }
            else if(verticalAlign == '1'){ //上对齐
                verticalAlignPos = pos_y
            }
            else if(verticalAlign == '2'){ //下对齐
                verticalAlignPos =verticalAlignPos - textInfo.desc
            }

            verticalAlignPos = verticalAlignPos/Store.zoomRatio
            horizonAlignPos = horizonAlignPos/Store.zoomRatio

            luckysheetTableContent.drawImage(
                luckysheet_CFiconsImg,
                l * 42,
                t * 32,
                32,
                32,
                pos_x/Store.zoomRatio ,
                verticalAlignPos,
                textInfo.textHeightAll/Store.zoomRatio,
                textInfo.textHeightAll/Store.zoomRatio
            )

            if(horizonAlign != '0' && horizonAlign != '2'){ //左对齐时 文本渲染空出一个图标的距离
                horizonAlignPos = horizonAlignPos + textInfo.textHeightAll/Store.zoomRatio
            }
        }

        //单元格 文本颜色
        luckysheetTableContent.fillStyle = menuButton.checkstatus(Store.flowdata, r, c , 'fc')

        //若单元格有交替颜色 文本颜色
        if(checksAF != null && checksAF[0] != null){
            luckysheetTableContent.fillStyle = checksAF[0]
        }
        //若单元格有条件格式 文本颜色
        if(checksCF != null && checksCF['textColor'] != null){
            luckysheetTableContent.fillStyle = checksCF['textColor']
        }

        //若单元格格式为自定义数字格式（[red]） 文本颜色为红色
        if(cell.ct && cell.ct.fa && cell.ct.fa.indexOf('[Red]') > -1 && cell.ct.t == 'n' && cell.v < 0){
            luckysheetTableContent.fillStyle = '#ff0000'
        }

        cellTextRender(
            textInfo,
            luckysheetTableContent,
            {
                pos_x:pos_x,
                pos_y:pos_y,
            }
        )


        luckysheetTableContent.restore()
    }

    if(cellOverflow_bd_r_render){

        // 右边框
        // 无论是否有背景色，都默认绘制右边框
        if(!Store.luckysheetcurrentisPivotTable && Store.showGridLines){
            luckysheetTableContent.beginPath()
            luckysheetTableContent.moveTo(
                (end_c + offsetLeft - 2 + bodrder05),
                (start_r + offsetTop)
            )
            luckysheetTableContent.lineTo(
                (end_c + offsetLeft - 2 + bodrder05),
                (end_r + offsetTop)
            )
            luckysheetTableContent.lineWidth = 1
            luckysheetTableContent.strokeStyle = luckysheetdefaultstyle.strokeStyle
            luckysheetTableContent.stroke()
            luckysheetTableContent.closePath()
        }
    }

    // 下边框
    // 无论是否有背景色，都默认绘制下边框
    if(!Store.luckysheetcurrentisPivotTable && Store.showGridLines){
        luckysheetTableContent.beginPath()
        luckysheetTableContent.moveTo(
            (start_c + offsetLeft - 1),
            (end_r + offsetTop - 2 + bodrder05)
        )
        luckysheetTableContent.lineTo(
            (end_c + offsetLeft - 1),
            (end_r + offsetTop - 2 + bodrder05)
        )
        luckysheetTableContent.lineWidth = 1
        luckysheetTableContent.strokeStyle = luckysheetdefaultstyle.strokeStyle
        luckysheetTableContent.stroke()
        luckysheetTableContent.closePath()
    }

    // 单元格渲染后
    method.createHookFunction('cellRenderAfter', Store.flowdata[r][c], {
        r:r,
        c:c,
        'start_r': cellsize[1],
        'start_c':cellsize[0],
        'end_r': cellsize[3] + cellsize[1],
        'end_c': cellsize[2] + cellsize[0]
    }, sheetmanage.getSheetByIndex(),luckysheetTableContent)
}

//溢出单元格渲染
let cellOverflowRender = function(r, c, stc, edc,luckysheetTableContent,scrollHeight,scrollWidth,offsetLeft,offsetTop,af_compute, cf_compute){
    //溢出单元格 起止行列坐标
    let start_r
    if (r == 0) {
        start_r = -scrollHeight - 1
    }
    else {
        start_r = Store.visibledatarow[r - 1] - scrollHeight - 1
    }

    let end_r = Store.visibledatarow[r] - scrollHeight

    let start_c
    if (stc == 0) {
        start_c = -scrollWidth
    }
    else {
        start_c = Store.visibledatacolumn[stc - 1] - scrollWidth
    }

    let end_c = Store.visibledatacolumn[edc] - scrollWidth

    //
    let cell = Store.flowdata[r][c]
    let cellWidth = end_c - start_c - 2
    let cellHeight = end_r - start_r - 2
    let space_width = 2, space_height = 2 //宽高方向 间隙

    let pos_x = start_c + offsetLeft
    let pos_y = start_r + offsetTop + 1

    let fontset = luckysheetfontformat(cell)
    luckysheetTableContent.font = fontset

    luckysheetTableContent.save()
    luckysheetTableContent.beginPath()
    luckysheetTableContent.rect(pos_x , pos_y, cellWidth , cellHeight )
    luckysheetTableContent.clip()
    luckysheetTableContent.scale(Store.zoomRatio,Store.zoomRatio)


    let textInfo = getCellTextInfo(cell , luckysheetTableContent, {
        cellWidth:cellWidth,
        cellHeight:cellHeight,
        space_width:space_width,
        space_height:space_height,
        r:r,
        c:c
    })

    //交替颜色
    let checksAF = alternateformat.checksAF(r, c, af_compute)
    //条件格式
    let checksCF = conditionformat.checksCF(r, c, cf_compute)

    //单元格 文本颜色
    luckysheetTableContent.fillStyle = menuButton.checkstatus(Store.flowdata, r, c , 'fc')

    //若单元格有交替颜色 文本颜色
    if(checksAF != null && checksAF[0] != null){
        luckysheetTableContent.fillStyle = checksAF[0]
    }
    //若单元格有条件格式 文本颜色
    if(checksCF != null && checksCF['textColor'] != null){
        luckysheetTableContent.fillStyle = checksCF['textColor']
    }

    cellTextRender(
        textInfo,
        luckysheetTableContent,
        {
            pos_x:pos_x,
            pos_y:pos_y,
        }
    )

    luckysheetTableContent.restore()

}

//获取表格渲染范围 溢出单元格
function getCellOverflowMap(canvas, col_st, col_ed, row_st, row_end){
    let map = {}

    let data = Store.flowdata

    for(let r = row_st; r <= row_end; r++){
        if(data[r]==null){
            continue
        }

        if(Store.cellOverflowMapCache[r]!=null){
            map[r] = Store.cellOverflowMapCache[r]
            continue
        }

        let hasCellOver = false

        for(let c = 0; c < data[r].length; c++){
            let cell = data[r][c]

            // if(Store.cellOverflowMapCache[r + '_' + c]!=null){
            //     map[r + '_' + c] = Store.cellOverflowMapCache[r + '_' + c];
            //     continue;
            // }

            if (Store.config['colhidden'] != null && Store.config['colhidden'][c] != null) {
                continue
            }

            if(cell != null && (!isRealNull(cell.v) || isInlineStringCell(cell) ) && cell.mc == null && cell.tb == '1'){

                //水平对齐
                let horizonAlign = menuButton.checkstatus(data, r, c, 'ht')


                let textMetricsObj = getCellTextInfo(cell, canvas,{
                    r:r,
                    c:c,
                })
                let textMetrics = 0
                if(textMetricsObj!=null){
                    textMetrics = textMetricsObj.textWidthAll
                }

                //canvas.measureText(value).width;

                let start_c = c - 1 < 0 ? 0 : Store.visibledatacolumn[c - 1]
                let end_c = Store.visibledatacolumn[c]

                let stc, edc

                if((end_c - start_c) < textMetrics){
                    if(horizonAlign == '0'){//居中对齐
                        let trace_forward = cellOverflow_trace(r, c, c - 1, 'forward', horizonAlign, textMetrics)
                        let trace_backward = cellOverflow_trace(r, c, c + 1, 'backward', horizonAlign, textMetrics)

                        if(trace_forward.success){
                            stc = trace_forward.c
                        }
                        else{
                            stc = trace_forward.c + 1
                        }

                        if(trace_backward.success){
                            edc = trace_backward.c
                        }
                        else{
                            edc = trace_backward.c - 1
                        }
                    }
                    else if(horizonAlign == '1'){//左对齐
                        let trace = cellOverflow_trace(r, c, c + 1, 'backward', horizonAlign, textMetrics)
                        stc = c

                        if(trace.success){
                            edc = trace.c
                        }
                        else{
                            edc = trace.c - 1
                        }
                    }
                    else if(horizonAlign == '2'){//右对齐
                        let trace = cellOverflow_trace(r, c, c - 1, 'forward', horizonAlign, textMetrics)
                        edc = c

                        if(trace.success){
                            stc = trace.c
                        }
                        else{
                            stc = trace.c + 1
                        }
                    }
                }
                else{
                    stc = c
                    edc = c
                }

                // if(((stc >= col_st && stc <= col_ed) || (edc >= col_st && edc <= col_ed)) && stc < edc){
                if(((stc <= col_ed) || (edc >= col_st)) && stc < edc){
                    let item = {
                        r: r,
                        stc: stc,
                        edc: edc
                    }

                    if(map[r]==null){
                        map[r] = {}
                    }

                    map[r][c] = item

                    // Store.cellOverflowMapCache[r + '_' + c] = item;

                    hasCellOver = true
                }
            }
        }

        if(hasCellOver){
            Store.cellOverflowMapCache[r] = map[r]
        }

    }

    return map
}

function cellOverflow_trace(r, curC, traceC, traceDir, horizonAlign, textMetrics){
    let data = Store.flowdata

    //追溯单元格列超出数组范围 则追溯终止
    if(traceDir == 'forward' && traceC < 0){
        return {
            success: false,
            r: r,
            c: traceC
        }
    }

    if(traceDir == 'backward' && traceC > data[r].length - 1){
        return {
            success: false,
            r: r,
            c: traceC
        }
    }

    //追溯单元格是 非空单元格或合并单元格 则追溯终止
    let cell = data[r][traceC]
    if(cell != null && (!isRealNull(cell.v) || cell.mc != null)){
        return {
            success: false,
            r: r,
            c: traceC
        }
    }

    let start_curC = curC - 1 < 0 ? 0 : Store.visibledatacolumn[curC - 1]
    let end_curC = Store.visibledatacolumn[curC]

    let w = textMetrics - (end_curC - start_curC)

    if(horizonAlign == '0'){//居中对齐
        start_curC -= w / 2
        end_curC += w / 2
    }
    else if(horizonAlign == '1'){//左对齐
        end_curC += w
    }
    else if(horizonAlign == '2'){//右对齐
        start_curC -= w
    }

    let start_traceC = traceC - 1 < 0 ? 0 : Store.visibledatacolumn[traceC - 1]
    let end_traceC = Store.visibledatacolumn[traceC]

    if(traceDir == 'forward'){
        if(start_curC < start_traceC){
            return cellOverflow_trace(r, curC, traceC - 1, traceDir, horizonAlign, textMetrics)
        }
        else if(start_curC < end_traceC){
            return {
                success: true,
                r: r,
                c: traceC
            }
        }
        else{
            return {
                success: false,
                r: r,
                c: traceC
            }
        }
    }

    if(traceDir == 'backward'){
        if(end_curC > end_traceC){
            return cellOverflow_trace(r, curC, traceC + 1, traceDir, horizonAlign, textMetrics)
        }
        else if(end_curC > start_traceC){
            return {
                success: true,
                r: r,
                c: traceC
            }
        }
        else{
            return {
                success: false,
                r: r,
                c: traceC
            }
        }
    }
}

function cellOverflow_colIn(map, r, c, col_st, col_ed){
    let colIn = false, //此单元格 是否在 某个溢出单元格的渲染范围
        colLast = false, //此单元格 是否是 某个溢出单元格的渲染范围的最后一列
        rowIndex, //溢出单元格 行下标
        colIndex, //溢出单元格 列下标
        stc,
        edc

    for(let rkey in map){
        for(let ckey in map[rkey]){
            rowIndex = rkey
            colIndex = ckey
            // rowIndex = key.substr(0, key.indexOf('_'));
            // colIndex = key.substr(key.indexOf('_') + 1);
            let mapItem = map[rkey][ckey]
            stc = mapItem.stc
            edc = mapItem.edc

            if(rowIndex == r){
                if(c >= stc && c <= edc){
                    colIn = true

                    if(c == edc || c == col_ed){
                        colLast = true
                        break
                    }
                }
            }
        }

        if(colLast){
            break
        }
    }

    return {
        colIn: colIn,
        colLast: colLast,
        rowIndex: rowIndex,
        colIndex: colIndex,
        stc: stc,
        edc: edc
    }
}

function cellTextRender(textInfo, ctx, option){
    if(textInfo==null){
        return
    }
    let values = textInfo.values
    let pos_x = option.pos_x, pos_y = option.pos_y
    if(values==null){
        return
    }
    // console.log(textInfo, pos_x, pos_y, values[0].width, values[0].left, ctx);

    // for(let i=0;i<values.length;i++){
    //     let word = values[i];
    //     ctx.font = word.style;
    //     ctx.fillText(word.content, (pos_x + word.left)/Store.zoomRatio, (pos_y+word.top)/Store.zoomRatio);
    // }

    // ctx.fillStyle = "rgba(255,255,0,0.2)";
    // ctx.fillRect((pos_x + values[0].left)/Store.zoomRatio, (pos_y+values[0].top-values[0].asc)/Store.zoomRatio, textInfo.textWidthAll, textInfo.textHeightAll)

    if(textInfo.rotate!=0 && textInfo.type!='verticalWrap'){
        ctx.save()
        ctx.translate((pos_x+textInfo.textLeftAll)/Store.zoomRatio, (pos_y+textInfo.textTopAll)/Store.zoomRatio)
        ctx.rotate(-textInfo.rotate * Math.PI / 180)
        ctx.translate(-(textInfo.textLeftAll+pos_x)/Store.zoomRatio, -(pos_y+textInfo.textTopAll)/Store.zoomRatio)
    }

    // ctx.fillStyle = "rgb(0,0,0)";
    for(let i=0;i<values.length;i++){
        let word = values[i]
        if(word.inline===true && word.style!=null){
            ctx.font = word.style.fontset
            ctx.fillStyle = word.style.fc
        }
        else{
            ctx.font = word.style
        }

        // 暂时未排查到word.content第一次会是object，先做下判断来渲染，后续找到问题再复原
        let txt = typeof word.content === 'object' ? word.content.m : word.content
        ctx.fillText(txt, (pos_x + word.left)/Store.zoomRatio, (pos_y+word.top)/Store.zoomRatio)


        if(word.cancelLine!=null){
            let c = word.cancelLine
            ctx.beginPath()
            ctx.moveTo(
                Math.floor((pos_x +c.startX)/Store.zoomRatio)+0.5 ,
                Math.floor((pos_y+c.startY)/Store.zoomRatio)+0.5 ,
            )
            ctx.lineTo(
                Math.floor((pos_x +c.endX)/Store.zoomRatio)+0.5 ,
                Math.floor((pos_y+c.endY)/Store.zoomRatio)+0.5 ,
            )
            ctx.lineWidth = Math.floor(c.fs/9)
            ctx.strokeStyle = ctx.fillStyle
            ctx.stroke()
            ctx.closePath()
        }

        if(word.underLine!=null){
            let underLines = word.underLine
            for(let a=0;a<underLines.length;a++){
                let item = underLines[a]
                ctx.beginPath()
                ctx.moveTo(
                    Math.floor((pos_x +item.startX)/Store.zoomRatio)+0.5 ,
                    Math.floor((pos_y+item.startY)/Store.zoomRatio)
                )
                ctx.lineTo(
                    Math.floor((pos_x +item.endX)/Store.zoomRatio)+0.5,
                    Math.floor((pos_y+ item.endY)/Store.zoomRatio)+0.5
                )
                ctx.lineWidth = Math.floor(item.fs/9)
                ctx.strokeStyle = ctx.fillStyle
                ctx.stroke()
                ctx.closePath()
            }
        }
    }
    // ctx.fillStyle = "rgba(0,0,0,0.2)";
    // ctx.fillRect((pos_x + values[0].left)/Store.zoomRatio, (pos_y+values[0].top-values[0].asc)/Store.zoomRatio, textInfo.textWidthAll, textInfo.textHeightAll)
    // ctx.fillStyle = "rgba(255,0,0,1)";
    // ctx.fillRect(pos_x+textInfo.textLeftAll-2, pos_y+textInfo.textTopAll-2, 4,4);
    if(textInfo.rotate!=0 && textInfo.type!='verticalWrap'){
        ctx.restore()
    }
}


export {
    luckysheetDrawgridRowTitle,
    luckysheetDrawgridColumnTitle,
    luckysheetDrawMain,
}
